#pragma once
#include<iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include"Logger.hpp"
#include"InetAddr.hpp"

const static int gsockfd=-1;
const static int backlog=16;

//模板继承模式
class Socket
{
public:
    virtual ~Socket()=default;
    virtual void CreateSocket()=0;
    virtual void BindSocket(uint16_t port)=0;
    virtual void ListenSocket()=0;
    virtual int Accept(InetAddr*addr)=0;
    virtual int SockFd()=0;
    virtual void Close()=0;
    virtual ssize_t Recv(std::string*out)=0;
    virtual ssize_t Send(const std::string&in)=0;
public:
    void BuildTcpSocket(uint16_t port)
    {
        CreateSocket();
        BindSocket(port);
        ListenSocket();
    }
};

enum
{
    OK,
    SOCKET_CREATE_ERRO,
    SOCKET_BIND_ERRO,
    SOCKET_LISTEN_ERRO
};

class TcpSocket:public Socket
{
public:
    TcpSocket():_sockfd(gsockfd)
    {}
    void CreateSocket()override
    {
        _sockfd=socket(AF_INET,SOCK_STREAM,0);
        if(_sockfd<0)
        {
            LOG(LogLevel::FATAL)<<"socket create失败";
            exit(SOCKET_CREATE_ERRO);
        }
        LOG(LogLevel::INFO)<<"socket create成功";
    }
    void BindSocket(uint16_t port)override
    {
        InetAddr peer(port);
        if(bind(_sockfd,peer.Addr(),peer.Len())!=0)
        {
            LOG(LogLevel::FATAL)<<"bind socket失败";
            exit(SOCKET_BIND_ERRO);
        }
        LOG(LogLevel::INFO)<<"bind socket成功";
    }
    void ListenSocket()override
    {
        if(listen(_sockfd,backlog)!=0)
        {
            LOG(LogLevel::FATAL)<<"listen socket失败";
            exit(SOCKET_LISTEN_ERRO);
        }
        LOG(LogLevel::INFO)<<"listen socket成功";
    }
    int Accept(InetAddr*addr)override
    {
        struct sockaddr_in clientaddr;
        socklen_t len=sizeof(clientaddr);
        int fd=accept(_sockfd,(struct sockaddr*)&clientaddr,&len);
        if(fd<0)
        {
            LOG(LogLevel::WARING)<<"accept socket失败";
            return -1;
        }
        addr->Init(clientaddr);
        LOG(LogLevel::INFO)<<"accept socket成功,"<<addr->ToString();
    }
    int SockFd()override
    {
        return _sockfd;
    }
    void Close()override
    {
        if(_sockfd>=0)
        {
            close(_sockfd);
        }
    }
    ssize_t Recv(std::string*out)override
    {
        char buffer[1024];
        buffer[0]=0;
        ssize_t n=recv(_sockfd,buffer,sizeof(buffer),0);
        if(n>0)
        {
            buffer[n]=0;
            *out+=buffer;
        }
        return n;
    }
    ssize_t Send(const std::string&in)override
    {
        return send(_sockfd,in.c_str(),in.size(),0);
    }
    ~TcpSocket(){}
private:
    int _sockfd;
};